package com.ship.dispatch.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ship.common.business.service.impl.BaseServiceImpl;
import com.ship.common.core.utils.BeanCopyUtils;
import com.ship.dispatch.bean.*;
import com.ship.dispatch.bo.HireTimeDetailsBO;
import com.ship.dispatch.bo.SpShipScheduleBO;
import com.ship.dispatch.mapper.ConShippingMapper;
import com.ship.dispatch.mapper.SpInformationMapper;
import com.ship.dispatch.mapper.SpShipScheduleMapper;
import com.ship.dispatch.service.SpInformationService;
import com.ship.dispatch.service.SpShipScheduleService;
import com.ship.dispatch.service.SpYearPlanSchemeDetailService;
import com.ship.dispatch.util.IDUtil;
import com.ship.dispatch.util.constant.ShipConstants;
import com.ship.dispatch.vo.SpShipScheduleVO;
import com.ship.dispatch.vo.leaseTermVO;
import liquibase.pro.packaged.P;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class SpShipScheduleServiceImpl extends BaseServiceImpl<SpShipScheduleMapper, SpShipSchedule> implements SpShipScheduleService {

    @Autowired
    private SpInformationService spInformationService;
    @Autowired
    private ConShippingMapper conShippingMapper;
    @Autowired
    private SpInformationMapper spInformationMapper;

    @Autowired
    private SpYearPlanSchemeDetailService spYearPlanSchemeDetailService;

    /**
     * 保存班期表
     */
    @Override
    public void saveShipSchedule(SpShipSchedule shipSchedule) {
        this.save(shipSchedule);
    }

    /**
     * 查询班期表信息
     *
     * @param spShipScheduleBO
     * @return
     */
    @Override
    public List<SpShipScheduleVO> selectShipSchedules(SpShipScheduleBO spShipScheduleBO) {
        List<SpShipScheduleVO> spShipScheduleVOs = new ArrayList<>();

        List<SpInformation> spInformations = spInformationMapper.selectList(
                new QueryWrapper<SpInformation>()
                        .eq("is_virtual", 0)
        );
        for (SpInformation spInformation : spInformations) {
            SpShipScheduleVO scheduleVO = new SpShipScheduleVO();
            scheduleVO.setShipName(spInformation.getNameOfVessel());
            scheduleVO.setImo(spInformation.getImo());

            JSONArray rentTimeSlot = new JSONArray();
            List<leaseTermVO> leaseTermVOS = new LinkedList<>();

            //处理租入时间段
            QueryWrapper<ConShipping> conShipWrapper = new QueryWrapper<>();
            conShipWrapper.in("status", 1, 2, 3);
            conShipWrapper.lt("starting_date_of_lease_begin", new Date());
            conShipWrapper.gt("redelivery_date_end", new Date());
            conShipWrapper.eq("imo", spInformation.getImo());
            conShipWrapper.in("contract_type", 1, 2 ,3 ,5);
            List<ConShipping> conShippings = conShippingMapper.selectList(conShipWrapper);
            for (ConShipping conShipping : conShippings) {
                if(StringUtils.isBlank(conShipping.getRentTimeSlot())){
                    continue;
                }
                JSONArray rentArray = JSONArray.parseArray(conShipping.getRentTimeSlot());
                if(conShipping.getContractType().intValue() == 1 || conShipping.getContractType().intValue() == 2){
                    //租入
                    if(StringUtils.isNotBlank(conShipping.getRentTimeSlot())){
                        rentTimeSlot.addAll(rentArray);
                    }
                }else if(conShipping.getContractType().intValue() == 3){
                    //租出
                    for (Object o : rentArray) {
                        JSONObject rentJson = JSONObject.parseObject(o.toString());
                        leaseTermVO leaseTermVO = new leaseTermVO();
                        leaseTermVO.setStart(rentJson.getDate("rentDateBegin"));
                        leaseTermVO.setEnd(rentJson.getDate("rentDateEnd"));
                        leaseTermVOS.add(leaseTermVO);
                    }

                }else if(conShipping.getContractType().intValue() == 5){
                    //off-hire
                    for (Object o : rentArray) {
                        JSONObject rentJson = JSONObject.parseObject(o.toString());
                        leaseTermVO leaseTermVO = new leaseTermVO();
                        leaseTermVO.setStart(rentJson.getDate("rentDateBegin"));
                        leaseTermVO.setEnd(rentJson.getDate("rentDateEnd"));
                        leaseTermVOS.add(leaseTermVO);
                    }
                }
            }

            scheduleVO.setRentTimeSlot(rentTimeSlot);
            scheduleVO.setLeaseTermVOS(leaseTermVOS);
            //舱容和租期
            if(spInformation.getStorageCapacity() != null){
                BigDecimal storageCapacity = spInformation.getStorageCapacity().multiply(BigDecimal.valueOf(0.985))
                        .subtract(BigDecimal.valueOf(500)).multiply(BigDecimal.valueOf(22.5))
                        .setScale(0, BigDecimal.ROUND_DOWN);
                scheduleVO.setStorageCapacity(storageCapacity);
                //生成年度计划，每船货上下浮动3.25%
                BigDecimal storageCapacityFloat = storageCapacity.multiply(BigDecimal.valueOf(0.0325))
                        .setScale(0, BigDecimal.ROUND_DOWN);
                BigDecimal maxStorageCapacity = storageCapacity.add(storageCapacityFloat);
                BigDecimal minStorageCapacity = storageCapacity.subtract(storageCapacityFloat);
                scheduleVO.setMaxStorageCapacity(maxStorageCapacity);
                scheduleVO.setMinStorageCapacity(minStorageCapacity);
            }
            spShipScheduleVOs.add(scheduleVO);
        }

        //增加虚拟船
        QueryWrapper<SpInformation> queryWrapperVir = new QueryWrapper<>();
        queryWrapperVir.eq("is_virtual", 1);
        List<SpInformation> virShip = spInformationMapper.selectList(queryWrapperVir);
        for (SpInformation spInformation : virShip) {
            SpShipScheduleVO shipScheduleVO = new SpShipScheduleVO();
            shipScheduleVO.setShipName(spInformation.getNameOfVessel());
            shipScheduleVO.setImo(spInformation.getImo());
            if(StringUtils.isNotBlank(spInformation.getRentTimeSlot())){
                shipScheduleVO.setRentTimeSlot(JSONArray.parseArray(spInformation.getRentTimeSlot()));
            }

            if(spInformation.getStorageCapacity() != null){
                BigDecimal storageCapacity = spInformation.getStorageCapacity().multiply(BigDecimal.valueOf(0.985))
                        .subtract(BigDecimal.valueOf(500)).multiply(BigDecimal.valueOf(22.5))
                        .setScale(0, BigDecimal.ROUND_DOWN);
                shipScheduleVO.setStorageCapacity(storageCapacity);
                //生成年度计划，每船货上下浮动3.25%
                BigDecimal storageCapacityFloat = storageCapacity.multiply(BigDecimal.valueOf(0.0325))
                        .setScale(0, BigDecimal.ROUND_DOWN);
                BigDecimal maxStorageCapacity = storageCapacity.add(storageCapacityFloat);
                BigDecimal minStorageCapacity = storageCapacity.subtract(storageCapacityFloat);
                shipScheduleVO.setMaxStorageCapacity(maxStorageCapacity);
                shipScheduleVO.setMinStorageCapacity(minStorageCapacity);
            }
            spShipScheduleVOs.add(shipScheduleVO);
        }

//        if (spShipScheduleVOs != null && spShipScheduleVOs.size() > 0) {
//            spShipScheduleVOs.stream().forEach(s -> {
//                QueryWrapper<SpShipSchedule> shipScheduleQueryWrapper = new QueryWrapper<>();
//                shipScheduleQueryWrapper.eq("ship_name", s.getShipName());
//                shipScheduleQueryWrapper.eq("imo", s.getImo());
//                if (spShipScheduleBO.getPlanId() != null) {
//                    shipScheduleQueryWrapper.eq("plan_id", spShipScheduleBO.getPlanId());
//                }
//                if (StringUtils.isNotBlank(spShipScheduleBO.getCreateBy())) {
//                    shipScheduleQueryWrapper.eq("create_by", spShipScheduleBO.getCreateBy());
//                }
//                List<SpShipSchedule> shipSchedules = this.getBaseMapper().selectList(shipScheduleQueryWrapper);
//                if (shipSchedules != null && shipSchedules.size() > 0) {
//                    s.setShipSchedules(shipSchedules);
//                    //获取上下浮动容量
//                    s.setMaxStorageCapacity(shipSchedules.get(0).getMaxStorageCapacity());
//                    s.setMinStorageCapacity(shipSchedules.get(0).getMinStorageCapacity());
//                }
//            });
//        }
        return spShipScheduleVOs;
    }

    /**
     * 修改班期表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateShipSchedule(Long schemeId) {
        List<SpYearPlanSchemeDetail> details = spYearPlanSchemeDetailService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<SpYearPlanSchemeDetail>().eq(SpYearPlanSchemeDetail::getSchemeId, schemeId));
        if (details.size() == 0) {
            return;
        }
        //先删除原始的数据再新增
        this.baseMapper.delete(new LambdaQueryWrapper<SpShipSchedule>().eq(SpShipSchedule::getPlanId,details.get(0).getPlanId()));
        for (SpYearPlanSchemeDetail schemeDetail : details) {
            //使用这个变量来判断这艘船是否再租出时间范围内，如果再就为true
            AtomicReference<Boolean> judge = new AtomicReference<>(false);
            //起租开始时间
            AtomicReference<Date> startingDateOfLeaseBegin = new AtomicReference<>();
            //还船结束时间
            AtomicReference<Date> redeliveryDateEnd = new AtomicReference<>();
            //租出时间，多条
            List<String> leaseTermStrs = new ArrayList<>();
            //从船运合同中获取信息
            List<ConShipping> conShippings = conShippingMapper.getByIMO(schemeDetail.getImo());
            if (conShippings != null && conShippings.size() > 0) {
                conShippings.stream().forEach(c -> {
                    if (c.getContractType() != null && c.getContractType().equals(3)) {
                        //租出
                        leaseTermStrs.add(DateUtil.format(c.getDeliveryDateBegin(), "yyyy-MM-dd HH:mm:ss") + "," + DateUtil.format(c.getDeliveryDateEnd(), "yyyy-MM-dd HH:mm:ss"));
                        //空载时间小于交船时间
                        if (c.getDeliveryDateBegin()!=null && !schemeDetail.getExpectedEmptyReturnWindow().before(c.getDeliveryDateBegin())) {
                            judge.set(true);
                            //装载时间大于还船时间
                            if (c.getDeliveryDateEnd()!=null && !schemeDetail.getExpectedLoadingDate().after(c.getDeliveryDateEnd())) {
                                judge.set(true);
                            }else{
                                judge.set(false);
                            }
                        }
                    } else {
                        schemeDetail.setShipContractId(c.getId());
                        schemeDetail.setShipContractName(c.getContractName());
                        schemeDetail.setShipTradeBody(c.getTradeBody());
                        schemeDetail.setShipContractType(c.getContractType());
                        if (c.getDeliveryDateBegin() != null) {
                            startingDateOfLeaseBegin.set(c.getDeliveryDateBegin());
                        }
                        redeliveryDateEnd.set(c.getRedeliveryDateEnd());
                    }
                    //off-hire状态，时间段不能生成货数.并且记录在船期表中
                    if(c.getStatus()!=null && c.getStatus().equals(5)){
                        if(StringUtils.isNotBlank(c.getHireTimeValue())){
                            List<HireTimeDetailsBO> hireTimeDetailsBOS = new ArrayList<>();
                            ObjectMapper objectMapper = new ObjectMapper();
                            try {
                                hireTimeDetailsBOS = objectMapper.readValue(c.getHireTimeValue(), new TypeReference<List<HireTimeDetailsBO>>() {
                                });
                                if(hireTimeDetailsBOS!=null && hireTimeDetailsBOS.size()>0){
                                    hireTimeDetailsBOS.stream().forEach(h->{
                                        //空载时间小于交船时间
                                        if (h.getStart()!=null && !schemeDetail.getExpectedEmptyReturnWindow().before(h.getStart())) {
                                            judge.set(true);
                                            //装载时间大于还船时间
                                            if (h.getEnd()!=null && !schemeDetail.getExpectedLoadingDate().after(h.getEnd())) {
                                                judge.set(true);
                                            }else{
                                                judge.set(false);
                                            }
                                        }
                                        leaseTermStrs.add(DateUtil.format(h.getStart(), "yyyy-MM-dd HH:mm:ss") + "," + DateUtil.format(h.getEnd(), "yyyy-MM-dd HH:mm:ss"));
                                    });
                                }
                            } catch (JsonProcessingException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                });
            }

            //保存船舶班期表
            SpShipSchedule spShipSchedule = new SpShipSchedule();
            BeanUtils.copyProperties(schemeDetail, spShipSchedule);
            spShipSchedule.setId(IDUtil.nextId());
            BigDecimal goodsQuantityNew = schemeDetail.getSingleGoodsQuantity();
            //生成年度计划，每船货上下浮动3.25%
            BigDecimal storageCapacityFloat = goodsQuantityNew.multiply(BigDecimal.valueOf(0.0325))
                    .setScale(0, BigDecimal.ROUND_DOWN);
            BigDecimal maxStorageCapacity = goodsQuantityNew.add(storageCapacityFloat);
            BigDecimal minStorageCapacity = goodsQuantityNew.subtract(storageCapacityFloat);
            spShipSchedule.setMaxStorageCapacity(maxStorageCapacity);
            spShipSchedule.setMinStorageCapacity(minStorageCapacity);
            spShipSchedule.setStorageCapacity(goodsQuantityNew);
            spShipSchedule.setExecuteStatus(0);
            if (startingDateOfLeaseBegin.get() != null) {
                spShipSchedule.setStartingDateOfLeaseBegin(startingDateOfLeaseBegin.get());
            }
            if (redeliveryDateEnd.get() != null) {
                spShipSchedule.setRedeliveryDateEnd(redeliveryDateEnd.get());
            }
            if (leaseTermStrs != null && leaseTermStrs.size() > 0) {
                spShipSchedule.setLeaseTermStr(leaseTermStrs.toString());
            }
            this.saveShipSchedule(spShipSchedule);
        }
    }
}
